import { debounce, throttle, forEach, includes } from '../_util/common';
import ATable from '../table';
import AInput from '../input';
import AButton from '../button';
import ASelect from '../select';
import AIcon from '../icon';
import APagination from '../pagination';
import Props, { generateInputFilterFunc } from './Props';

const pager = {
  currPage: 1,
  pageSize: 25,
};

export default {
  name: 'CTable',
  props: Props(),
  data() {
    return {
      tableLoading: false,
      actualTableProp: {},
      pager: {
        currPage: pager.currPage,
        pageSize: pager.pageSize,
        totalCount: 0,
        totalPage: 0,
      },
    };
  },
  computed: {
    noMaxHeight() {
      return this.maxHeight === 'none';
    },
    isDynamicHeight() {
      return /^calc\(.*\)$/.test(this.maxHeight);
    },
    inputFilterFunc() {
      return generateInputFilterFunc(this.formatInputFilter);
    },
  },
  watch: {
    tableData: {
      //eslint-disable-next-line
      handler(newVal, oldVal) {
        // this.oldTableData = oldVal;
        !this.noMaxHeight && setTimeout(this.syncTable, 10, newVal);
      },
      deep: true,
      immediate: true,
    },
    tableProp: {
      handler(props) {
        this.actualTableProp = {
          ...props,
          pagination: props.pagination || false,
        };
        if (props.customRow) {
          this.actualTableProp.customRow = (...args) => {
            let timer = null;
            let mousedownStartTime = null;
            let rowProps = props.customRow(...args);
            return {
              ...rowProps,
              on: {
                ...rowProps.on,
                click: (...clickArgs) => {
                  if (Date.now() > mousedownStartTime + 300) {
                    //间隔大于300ms
                    return;
                  }
                  if (timer) {
                    clearTimeout(timer);
                    timer = null;
                  } else {
                    timer = setTimeout(() => {
                      timer = null;
                      rowProps.on.click && rowProps.on.click(...clickArgs);
                    }, 300);
                  }
                },
                mousedown: (...mousedownArgs) => {
                  mousedownStartTime = Date.now();
                  rowProps.on.mousedown && rowProps.on.mousedown(...mousedownArgs);
                },
              },
            };
          };
        }
      },
      deep: true,
      immediate: true,
    },
    pagerOption: {
      handler(newVal) {
        this.pager.pageSize = newVal.pageSize || pager.pageSize;
      },
      deep: true,
      immediate: true,
    },
  },
  created() {
    this.getList();

    if (!this.noMaxHeight) {
      this.debounceFn = debounce(() => {
        this.syncTable(this.tableData);
      }, 100);

      if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('resize', this.debounceFn);
      } else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onresize', this.debounceFn);
      }
    }
  },
  updated() {
    // if (this.oldTableData === this.tableData) {
    //   this.noMaxHeight || this.debounceFn();
    // } else {
    //   this.oldTableData = this.tableData;
    // }
  },
  beforeDestroy() {
    if (!this.noMaxHeight) {
      if (typeof window.removeEventListener !== 'undefined') {
        window.removeEventListener('resize', this.debounceFn);
      } else if (typeof window.detachEvent !== 'undefined') {
        window.detachEvent('onresize', this.debounceFn);
      }
    }
  },
  methods: {
    syncTable(data = []) {
      //没有表头
      if (!this.tableColumns || this.tableColumns.length === 0) {
        return;
      }
      /**
       * 源表格
       */
      if (!this.$refs.sourceTable) {
        return;
      }
      let sourceTableWrapper = this.$refs.sourceTable.$el;
      let sourceTableTHead = sourceTableWrapper.querySelector('table thead');
      let sourceTableTHeadWidth = sourceTableTHead.offsetWidth;
      let sourceTableTHeadHeight = sourceTableTHead.offsetHeight;
      //源表格各项表头的宽度
      let sourceTableThWidth = [];
      forEach(sourceTableTHead.querySelector('tr').childNodes, itemNode => {
        sourceTableThWidth.push(itemNode.offsetWidth);
      });
      /**
       * 目标表格
       */
      let targetTable = this.$refs.targetTable.$el;
      let colGroups = targetTable.querySelectorAll('table colgroup');

      // 表格td内的colgroup
      let innerColGroups = targetTable.querySelectorAll('td colgroup');

      let targetTableBody = targetTable.querySelector('.ant-table-body');
      let targetTablePlaceholder = targetTable.querySelector('.ant-table-placeholder');

      /**
       * thead不会有滚动条
       * 优先设置thead整体宽度及每一个col的宽度，因为此处有可能导致表头文字换行，从而影响maxHeight的计算
       */
      let theadTable = targetTable.querySelector('.ant-table-header table');
      theadTable.style.width = `${sourceTableTHeadWidth}px`;

      forEach(colGroups, itemColGroup => {
        // 排除table内部的其他table，不让他们受到更改style的影响
        if (!includes(innerColGroups, itemColGroup)) {
          forEach(itemColGroup.childNodes, (item, index, arr) => {
            if (index < arr.length - 1) {
              let currentWidth = sourceTableThWidth[index];
              item.style.width = `${currentWidth}px`;
            } else {
              //重置最后一列
              item.style.width = `unset`;
              item.style.minWidth = `unset`;
            }
            // item.style.minWidth = 'auto';
          });
        }
      });

      //计算默认高度maxHeight
      let leftContent =
        typeof this.contentWrapper === 'string'
          ? window.document.body.querySelector(this.contentWrapper)
          : this.contentWrapper();
      let leftContentSize = leftContent.getBoundingClientRect();

      let tableBodySize = targetTableBody.getBoundingClientRect();
      //默认表格最大高度：减去tBody到浏览器上边沿的距离、页面实际高度 + 顶部导航栏高度 - tBody底部到浏览器上边沿的距离、冗余6px
      let defaultMaxHeight = `calc(100vh - ${tableBodySize.top +
        (leftContentSize.bottom - tableBodySize.bottom)}px - 6px)`;
      //先执行这一行保证滚动条出现
      let maxHeight = this.maxHeight
        ? this.translateMaxHeightToTBodyHeight(sourceTableTHeadHeight)
        : defaultMaxHeight;
      let minHeight = this.maxHeight
        ? this.translateMaxHeightToTBodyHeight(sourceTableTHeadHeight, true, data)
        : defaultMaxHeight;
      targetTableBody.style.maxHeight = maxHeight;
      if (!this.maxHeight || this.isDynamicHeight) {
        targetTableBody.style.minHeight = minHeight;
      }

      //表格没有数据依旧需要同步thead，以及设置高度
      if (!data || data.length === 0) {
        //fix 接口由正常且有数据 => 报错
        if (targetTablePlaceholder) {
          targetTablePlaceholder.style.transform = `translateY(-${targetTableBody.offsetHeight /
            2}px)`;
        }
        //fix 滚动到最右边 => 筛选空数据
        theadTable.style.transform = 'translateX(0px)';
        return;
      }

      /**
       * 记录页面右侧内容区滚动条的变化过程
       */
      let innerHeight = window.innerHeight;
      let pageHasScroll = leftContentSize.bottom > innerHeight;
      let currentHasScroll = leftContent.offsetHeight + leftContentSize.top > innerHeight;
      //如果有滚动条，则为滚动条的宽度，如果没有则为0
      let scrollWidth = targetTableBody.offsetWidth - targetTableBody.clientWidth;
      let tbodyTable = targetTableBody.querySelector('table');
      //如果在同步之前右侧内容区有滚动条，则无需考虑tbody的滚动条，否则需要减去滚动条的宽度
      /**
       * 如果maxHeight修改前后均有滚动条或均无滚动条，此时需要减去scrollWidth
       * 否则肯定是修改前有滚动条，修改后没有滚动条
       */
      tbodyTable.style.width = `${
        pageHasScroll !== currentHasScroll
          ? sourceTableTHeadWidth
          : sourceTableTHeadWidth - scrollWidth
      }px`;

      let currentScrollLeft = 0;
      //tbody横向滚动，同步移动thead
      targetTableBody.onscroll = throttle(function(e) {
        if (currentScrollLeft !== e.target.scrollLeft) {
          currentScrollLeft = e.target.scrollLeft;
          theadTable.style.transform = `translateX(-${currentScrollLeft}px)`;
        }
      }, 24);
      //小窗口横向滚动一段距离，转至大窗口后需重置样式
      theadTable.style.transform = `translateX(-${targetTableBody.scrollLeft}px)`;
    },
    translateMaxHeightToTBodyHeight(tHeadHeight, isMinHeight, data) {
      if (this.isDynamicHeight) {
        // 冗余6px
        return this.maxHeight.replace(
          /\)$/,
          ` - ${tHeadHeight}px${isMinHeight && data.length === 0 ? ' - 166px' : ''} - 6px)`,
        );
      }
      return `calc(${this.maxHeight} - ${tHeadHeight}px - 6px)`;
    },
    filterOption(input, option) {
      return (
        option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
      );
    },
    totalPage() {
      let { totalCount, totalPage } = this.pager;
      return '共 ' + totalPage + ' 页 / ' + totalCount + '条数据';
    },
    //检索
    handleSearch(confirm) {
      confirm();
    },
    //重置
    handleReset(clearFilters) {
      clearFilters();
    },
    pagerChange(page, pageSize) {
      this.pager.currPage = page;
      this.pager.pageSize = pageSize;
      this.getList();
    },
    handleTableChange(pagination, filters, sorter) {
      this.$emit('tableChange', [pagination, filters, sorter]);
      this.pager.currPage = 1;
      this.getAsyncList();
    },
    getList() {
      if (!this.ajaxFn) {
        return;
      }
      let param = this.needPagination
        ? {
            currPage: this.pager.currPage,
            pageSize: this.pager.pageSize,
            entity: this.filters,
          }
        : this.filters;

      this.tableLoading = true;
      this.ajaxFn(param)
        .then(
          res => {
            if (!res) {
              // fix null
              return;
            }
            if (this.needPagination) {
              res.records = res.records || [];
              this.pager.totalPage = res.totalPage;
              this.pager.totalCount = res.totalCount;
            }
            this.$emit('updateTableData', res);
          },
          () => {
            this.syncTable();
          },
        )
        .finally(() => {
          this.tableLoading = false;
        });
    },
    getAsyncList() {
      this.$nextTick(() => {
        this.getList();
      });
    },
    getResetList() {
      this.pager.currPage = 1;
      this.getAsyncList();
    },
  },
  render(h) {
    let { inputFilterFunc } = this;

    let sourceTableScopeSlot = {
      // 此处会影响浏览器对宽度的计算，保持占位，保持一致
      // 输入框占位
      inputFilter: () => <div></div>,
      inputFilterIcon: () => <AIcon type="search" />,

      // 多选下拉筛选占位 - 防止因为没有对应的scopeSlot报错
      multiSelect: () => <div></div>,
      multiSelectIcon: () => <AIcon type="filter" theme="filled" />,

      ...this.$scopedSlots,
    };
    let sourceTableOption = {
      ref: 'sourceTable',
      class: 'sourceTable',
      props: {
        rowKey: this.rowKey,
        columns: this.tableColumns,
        dataSource: this.tableData,
        // actualTableProp包括rowSelection属性的时候会给表格多添加一列，若是去掉此处的v-bind会导致同步thead异常
        ...this.actualTableProp,
      },
      scopedSlots: sourceTableScopeSlot,
    };
    let SourceTable = this.noMaxHeight ? null : <ATable {...sourceTableOption} />;

    // 输入框搜索
    let inputFilter = ({ setSelectedKeys, selectedKeys, confirm, clearFilters, column }) => {
      return (
        <div class="filter-input-wrapper">
          <AInput
            class="filter-input"
            {...{
              props: {
                value: selectedKeys[0],
                placeholder: column.placeholder || `请输入${column.title}`,
              },
              on: {
                change: e => setSelectedKeys(e.target.value ? [e.target.value] : []),
                pressEnter: () => {
                  setSelectedKeys(selectedKeys[0] ? [inputFilterFunc(selectedKeys[0])] : []);
                  this.handleSearch(confirm);
                },
              },
            }}
          />
          <div class="filter-btn-wrapper">
            <AButton
              type="primary"
              icon="search"
              {...{
                on: {
                  click: () => {
                    setSelectedKeys(selectedKeys[0] ? [inputFilterFunc(selectedKeys[0])] : []);
                    this.handleSearch(confirm);
                  },
                },
              }}
            >
              检索
            </AButton>
            <AButton {...{ on: { click: () => this.handleReset(clearFilters) } }}>重置</AButton>
          </div>
        </div>
      );
    };
    // 多选下拉筛选
    let multiSelect = ({ setSelectedKeys, selectedKeys, confirm, clearFilters, column }) => {
      return (
        <div class="multi-select-wrapper">
          <div class="filter-btn-wrapper">
            <AButton
              type="primary"
              icon="search"
              {...{ on: { click: () => this.handleSearch(confirm) } }}
            >
              检索
            </AButton>
            <AButton {...{ on: { click: () => this.handleReset(clearFilters) } }}>重置</AButton>
          </div>
          <ASelect
            {...{
              class: 'multi-select',
              props: {
                showSearch: true,
                mode: column.filterMultiple === false ? 'default' : 'multiple',
                value: selectedKeys,
                filterOption: this.filterOption,
                placeholder: column.placeholder || `请选择${column.title}`,
              },
              on: {
                change: val => setSelectedKeys(column.filterMultiple === false ? [val] : val),
              },
            }}
          >
            {column.multiSelectFilter.map(select => {
              return <ASelect.Option {...{ key: select.id }}>{select.name}</ASelect.Option>;
            })}
          </ASelect>
        </div>
      );
    };
    // 插槽
    let targetTableScopeSlot = {
      inputFilter,
      inputFilterIcon: filtered => {
        return <AIcon type="search" {...{ style: { color: filtered ? '#108ee9' : undefined } }} />;
      },
      multiSelect,
      multiSelectIcon: filtered => {
        return (
          <AIcon
            type="filter"
            theme="filled"
            {...{ style: { color: filtered ? '#108ee9' : undefined } }}
          />
        );
      },
      ...this.$scopedSlots,
    };
    let targetTableOption = {
      ref: 'targetTable',
      class: [
        'targetTable',
        this.tableData.length > 0 ? 'tbody-min-height' : 'table-no-data table-scroll-x',
        this.actualTableProp.customRow ? 'tbody-has-next' : '',
        this.noMaxHeight ? 'table-no-max-height' : '',
      ],
      props: {
        rowKey: this.rowKey,
        columns: this.tableColumns,
        dataSource: this.tableData,
        loading: this.tableLoading,
        scroll: this.noMaxHeight ? {} : { y: true },
        ...this.actualTableProp,
      },
      on: {
        change: this.handleTableChange,
        ...this.tableListener,
      },
      scopedSlots: targetTableScopeSlot,
    };
    let TargetTable = <ATable {...targetTableOption} />;

    let Pagination = this.needPagination ? (
      <APagination
        {...{
          props: {
            current: this.pager.currPage,
            pageSize: this.pager.pageSize,
            total: this.pager.totalCount,
            showTotal: this.totalPage,
            showQuickJumper: true,
          },
          on: {
            change: this.pagerChange,
            'change.current': currPage => {
              this.pager.currPage = currPage;
            },
            'update:pageSize': pageSize => {
              this.pager.pageSize = pageSize;
            },
          },
        }}
      />
    ) : null;

    return (
      <div class="customTable">
        {SourceTable}
        {TargetTable}
        {Pagination}
      </div>
    );
  },
};
